package com.szjz.elasticsearch.eshelper.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.szjz.elasticsearch.eshelper.base.wrapper.WrapperServiceImpl;
import com.szjz.elasticsearch.eshelper.page.Page;
import com.szjz.elasticsearch.eshelper.service.ESService;
import com.szjz.elasticsearch.eshelper.util.RandomUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * @author shibo
 * @desc 基础服务实现类
 * @date 2020/6/3 周三
 */

@Slf4j
@Service
public class BaseESServiceImpl<T extends BaseESEntity> extends WrapperServiceImpl<T> implements BaseESService<T> {

    @Autowired
    private ESService esService;

    /**
     * 新增数据
     */
    @SneakyThrows
    @Override
    public Boolean save(T t) {
        String indexName = getIndexName();
        IndexResponse indexResponse = null;
        try {
            IndexRequest request = new IndexRequest(indexName);
            String id = RandomUtils.getUUID();
            request.id(id);
            t.setDocId(id);
            if (t.getCrtTime() == null) {
                t.setCrtTime(Calendar.getInstance().getTime());
            }
            if (t.getUpdTime() == null) {
                t.setUpdTime(Calendar.getInstance().getTime());
            }
            request.source(JSONArray.toJSONString(t), XContentType.JSON);
            indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            if (!esService.indexExist(indexName)) {
                Boolean isSuccess = esService.createIndex(getEntityClass());
                log.error("【save】error: 索引库{}不存在, 重新创建{}", indexName, isSuccess ? "成功！" : "失败！");
            }
        }
        DocWriteResponse.Result result = indexResponse.getResult();
        if (!"CREATED".equals(result.toString())) {
            log.error("【ES save】数据新增失败！ id: {}", t.getId());
            return false;
        } else {
            return true;
        }
    }


    /**
     * 保存or更新
     */
    @Override
    public Boolean saveOrUpdate(T t) {
        if (t == null) {
            log.warn("【ES saveOrUpdate】t can not be null");
            return false;
        }
        if (StringUtils.isEmpty(t.getId())) {
            log.warn("【ES saveOrUpdate】t'id can not be null");
            return false;
        }
        return saveOrUpdateBatch(Collections.singletonList(t));
    }

    /**
     * 按照时间分片 保存or更新
     */
    @Override
    public Boolean saveOrUpdateByDate(T t) {
        if (t == null) {
            log.warn("【ES saveOrUpdateByDate】t can not be null");
            return false;
        }
        if (StringUtils.isEmpty(t.getId())) {
            log.warn("【ES saveOrUpdateByDate】t'id can not be null");
            return false;
        }
        return saveOrUpdateBatchByDate(Collections.singletonList(t));
    }

    /**
     * 批量插入数据
     *
     * @param ts
     */
    @Override
    @SneakyThrows
    @Deprecated
    public Boolean saveBatch(List<T> ts) {
        BulkRequest bulkRequest = new BulkRequest();
        String indexName = getIndexName();
        ts.forEach(t -> {
            String uuid = RandomUtils.getUUID();
            t.setDocId(uuid);
            if (t.getCrtTime() == null) {
                t.setCrtTime(Calendar.getInstance().getTime());
            }
            if (t.getUpdTime() == null) {
                t.setUpdTime(Calendar.getInstance().getTime());
            }
            bulkRequest.add(new IndexRequest(indexName).id(uuid).source(JSON.toJSONString(t), XContentType.JSON));
        });
        BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (!bulkResponse.hasFailures()) {
            log.debug("【ES saveBatch】数据批量插入成功！size: {}", ts.size());
            return true;
        } else {
            log.error("【ES saveBatch】数据批量插入失败！size: {}", ts.size());
            return false;
        }
    }


    /**
     * 批量插入or更新数据
     * docId = _id
     *
     * @param ts
     */
    @SneakyThrows
    @Override
    public Boolean saveOrUpdateBatch(List<T> ts) {
        if (CollectionUtils.isEmpty(ts)) {
            log.warn("【ES saveOrUpdateBatch】ts list Can not be empty !");
            return false;
        }
        List<T> collect = ts.stream().filter(t -> StringUtils.isEmpty(t.getId())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)) {
            throw new RuntimeException("【ES saveOrUpdateBatch】id is null or ''");
        }
        BulkResponse bulk = null;
        BulkRequest bulkRequest = new BulkRequest();
        String indexName = getIndexName();
        for (T t : ts) {
            t.setDocId(t.getId());
            if (t.getCrtTime() == null) {
                t.setCrtTime(Calendar.getInstance().getTime());
            }
            if (t.getUpdTime() == null) {
                t.setUpdTime(Calendar.getInstance().getTime());
            }
            IndexRequest indexRequest = new IndexRequest(indexName).source(getSourceMap(t));
            UpdateRequest updateRequest = new UpdateRequest(indexName, t.getDocId()).doc(indexRequest).docAsUpsert(true);
            bulkRequest.add(updateRequest);
        }
        try {
            bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert bulk != null;
        if (bulk.hasFailures()) {
            if (!esService.indexExist(indexName)) {
                Boolean isSuccess = esService.createIndex(indexName, getEntityClass());
                log.info("【ES saveOrUpdateBatch】索引库{}不存在, 重新创建{}", indexName, isSuccess ? "成功！" : "失败！");
                if (isSuccess) {
                    saveOrUpdateBatch(ts);
                } else {
                    throw new RuntimeException("【ES saveOrUpdateBatch】索引库 " + indexName + " 创建失败");
                }
            } else {
                log.error("【ES saveOrUpdateBatch】保存失败原因:{}", bulk.buildFailureMessage());
                log.error("【ES saveOrUpdateBatch】失败 重新保存！indexName: {} size: {}", indexName, ts.size());
                // saveOrUpdateBatch(ts);
            }
            return false;
        } else {
            log.debug("【ES saveOrUpdateBatch】成功 ！size: {}", ts.size());
            return true;
        }
    }

    /**
     * 按照时间分片批量插入or更新数据
     * 按照数据的创建时间来分片
     * ts中的数据创建时间必须是同一天的
     * docId = _id
     *
     * @param ts
     */
    @SneakyThrows
    @Override
    public Boolean saveOrUpdateBatchByDate(List<T> ts) {
        if (CollectionUtils.isEmpty(ts)) {
            log.warn("【ES saveOrUpdateBatchByDate】ts list Can not be empty !");
            return false;
        }
        List<T> crtTimes = ts.stream().filter(t -> t.getCrtTime() == null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(crtTimes)) {
            log.warn("【ES saveOrUpdateBatchByDate】crtTimes : {}", crtTimes);
            log.warn("【ES saveOrUpdateBatchByDate】There are elements in the collection whose crtTime time is null!");
            throw new RuntimeException("There are elements in the collection whose crtTime time is null!");
        }
        List<T> ids = ts.stream().filter(t -> t.getId() == null).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(ids)) {
            log.warn("【ES saveOrUpdateBatchByDate】ids : {}", ids);
            log.warn("【ES saveOrUpdateBatchByDate】The attribute 'id' in the collection cannot be null!");
            throw new RuntimeException("The attribute 'id' in the collection cannot be null!");
        }
        Map<Integer, List<T>> collect = ts.stream().collect(Collectors.groupingBy(item -> item.getCrtTime().getDay()));
        for (Map.Entry<Integer, List<T>> entry : collect.entrySet()) {
            // Integer key = entry.getKey();
            List<T> list = entry.getValue();
            // log.info("key:{} size ：{} crtTime: {} list:{} ", key, list.size(), list.get(0).getCrtTime(), list.stream().map(t -> t.getCrtTime()).collect(Collectors.toList()));
            BulkRequest bulkRequest = new BulkRequest();
            BulkResponse bulkResponse = null;
            String indexName = getIndexName(list.get(0).getCrtTime());
            for (T t : list) {
                t.setDocId(t.getId());
                if (t.getUpdTime() == null) {
                    t.setUpdTime(Calendar.getInstance().getTime());
                }
                IndexRequest indexRequest = new IndexRequest(indexName).source(getSourceMap(t));
                UpdateRequest updateRequest = new UpdateRequest(indexName, t.getDocId()).doc(indexRequest).docAsUpsert(true);
                bulkRequest.add(updateRequest);
            }
            bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            assert bulkResponse != null;
            if (bulkResponse.hasFailures()) {
                if (!esService.indexExist(indexName)) {
                    Boolean isSuccess = esService.createIndex(indexName, getEntityClass());
                    log.info("【ES saveOrUpdateBatchByDate】索引库 {} 不存在, 重新创建{}", indexName, isSuccess ? "成功！" : "失败！");
                    if (isSuccess) {
                        saveOrUpdateBatchByDate(ts);
                    } else {
                        throw new RuntimeException("【ES saveOrUpdateBatchByDate】索引库 " + indexName + " 创建失败");
                    }
                } else {
                    log.error("【ES saveOrUpdateBatch】保存失败原因:{}", bulkResponse.buildFailureMessage());
                    // log.error("【ES saveOrUpdateBatchByDate】失败！重新保存 indexName: {} size: {} data：{}", indexName, list.size(), list.get(0));
                    // saveOrUpdateBatchByDate(ts);
                }
                return false;
            } else {
                log.debug("【ES saveOrUpdateBatchByDate】成功！indexName: {} size: {}", indexName, list.size());
            }
        }
        return true;
    }


    /**
     * 删除数据
     *
     * @param docId es 的 _id
     * @return
     */
    @SneakyThrows
    @Override
    public Boolean deleteByDocId(String docId) {
        DeleteRequest deleteRequest = new DeleteRequest(getIndexName(), docId);
        deleteRequest.timeout("3s");
        DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        RestStatus status = deleteResponse.status();
        if ("OK".equals(status.toString())) {
            log.debug("【ES deleteByDocId】数据删除成功！id: {}", docId);
            return true;
        } else if ("NOT_FOUND".equals(status.toString())) {
            log.warn("【ES deleteByDocId】数据不存在！id: {}", docId);
            return false;
        } else {
            log.error("【ES deleteByDocId】数据删除失败！id: {}", docId);
            return false;
        }
    }

    /**
     * 删除数据
     * 默认删除当天索引库的数据
     *
     * @param id 业务id
     * @return
     */
    @SneakyThrows
    @Override
    public Boolean deleteById(String id) {
        T t = selectById(id).get(0);
        if (t != null) {
            DeleteRequest deleteRequest = new DeleteRequest(getIndexName(), t.getDocId());
            deleteRequest.timeout("3s");
            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            RestStatus status = deleteResponse.status();
            if ("OK".equals(status.toString())) {
                log.debug("【ES deleteById】数据删除成功！id: {}", t.getDocId());
                return true;
            } else if ("NOT_FOUND".equals(status.toString())) {
                log.warn("【ES deleteById】数据不存在！id: {}", t.getDocId());
                return false;
            } else {
                log.error("【ES deleteById】数据删除失败！id: {}", t.getDocId());
                return false;
            }
        }
        return false;
    }

    /**
     * 批量删除数据
     *
     * @param ids es 的 _id
     */
    @Override
    public Boolean deleteBatch(List<String> ids) {
        BulkRequest bulkRequest = new BulkRequest();
        String indexName = getIndexName();
        ids.forEach(docId -> {
            bulkRequest.add(new DeleteRequest(indexName, docId));
        });
        BulkResponse bulkResponse = null;
        try {
            bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (!bulkResponse.hasFailures()) {
            log.debug("【ES deleteBatch】批量删除数据成功！size: {}", ids.size());
            return true;
        } else {
            log.error("【ES deleteBatch】批量删除数据失败！size: {}", ids.size());
            return false;
        }
    }


    /**
     * 更新数据
     */
    @SneakyThrows
    @Override
    public Boolean update(T t) {
        if (!dataIsExist(t.getDocId())) {
            throw new RuntimeException("【ES update】数据不存在");
        }
        UpdateRequest updateRequest = new UpdateRequest(getIndexName(), t.getDocId());
        updateRequest.timeout("5s");
        t.setUpdTime(Calendar.getInstance().getTime());
        updateRequest.doc(JSON.toJSONString(t), XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        RestStatus status = update.status();
        if ("OK".equals(status.toString())) {
            log.debug("【ES update】数据更新成功：{}", JSON.toJSONString(t));
            return true;
        } else {
            log.error("【ES update】数据更新失败！");
            return false;
        }
    }


    /**
     * 查询
     *
     * @param id 业务id
     * @return
     */
    @Override
    @SneakyThrows
    public List<T> selectById(Object id) {
        if (id == null) {
            return null;
        }
        // 创建 searchRequest
        SearchRequest searchRequest = new SearchRequest(getIndexName());
        // 指定查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("id", id));
        // 组装sql
        sourceBuilder.query(boolQueryBuilder);
        searchRequest.source(sourceBuilder);
        log.debug("DSL: {}", sourceBuilder.toString());
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
//        if (hits.length > 1) {
//            log.error("通过唯一id: {} 查询的结果数量不能大于1", id);
//            throw new RuntimeException("结果不唯一");
//        }
//        if (hits.length == 0) {
//            return null;
//        }
        List<T> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            list.add(JSON.parseObject(hit.getSourceAsString(), getEntityClass()));
        }
        return list;
    }


    /**
     * count 等值查询数量
     *
     * @param t 将要查询的条件封装到t的属性中
     * @return
     */
    @Override
    @SneakyThrows
    public Long count(T t) {
        Map<String, Object> validValue = getValidValue(t);
        CountRequest countRequest = new CountRequest(getIndexName());
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        validValue.forEach((name, value) -> {
            boolQueryBuilder.filter(termQuery(name, value));
        });
        countRequest.query(boolQueryBuilder);
        CountResponse count = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        log.debug("【count】结果：{}", count);
        return count.getCount();
    }

    /**
     * count 等值查询数量
     *
     * @param map 将要查询的条件封装map中
     * @return
     */
    @Override
    @SneakyThrows
    public Long count(Map<String, Object> map) {
        CountRequest countRequest = new CountRequest(getIndexName());
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        map.forEach((name, value) -> {
            boolQueryBuilder.filter(termQuery(name, value));
        });
        countRequest.query(boolQueryBuilder);
        CountResponse count = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
        log.debug("【count】结果：{}", count);
        return count.getCount();
    }


    /**
     * 查询
     *
     * @param docId = _id
     * @return
     */
    @Override
    @SneakyThrows
    public T selectByDocId(String docId) {
        if (docId == null) {
            return null;
        }
        GetRequest request = new GetRequest(getIndexName(), docId);
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        String sourceAsString = response.getSourceAsString();
        T t = JSON.parseObject(sourceAsString, getEntityClass());
        return t;
    }

    /**
     * 批量查询
     *
     * @param docIds es 的 _id
     * @return
     */
    @Override
    @SneakyThrows
    public List<T> selectByDocIds(List<String> docIds) {
        if (docIds == null || docIds.size() == 0) {
            return null;
        }
        String[] idList = docIds.toArray(new String[]{});
        SearchRequest searchRequest = new SearchRequest(getIndexName());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.idsQuery().addIds(idList));
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<T> list = new ArrayList<>(hits.length);
        Arrays.stream(hits).forEach(hit -> list.add(JSON.parseObject(hit.getSourceAsString(), getEntityClass())));
        return list;
    }

    /**
     * 批量查询
     *
     * @param ids 业务id
     * @return
     */
    @Override
    @SneakyThrows
    public List<T> selectByIds(List<String> ids) {
        if (ids == null || ids.size() == 0) {
            return null;
        }
        String[] idList = ids.toArray(new String[]{});
        SearchRequest searchRequest = new SearchRequest(getIndexName());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.termsQuery("id", idList));
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<T> list = new ArrayList<>(hits.length);
        Arrays.stream(hits).forEach(hit -> list.add(JSON.parseObject(hit.getSourceAsString(), getEntityClass())));
        return list;
    }

    /** ======================================================== */

    /**
     * 新增数据
     */
    @SneakyThrows
    @Override
    public Boolean saveByDate(T t) {
        String indexName = getIndexName(t.getCrtTime());
        IndexResponse indexResponse = null;
        try {
            IndexRequest request = new IndexRequest(indexName);
            String id = RandomUtils.getUUID();
            request.id(id);
            t.setDocId(id);
            if (t.getCrtTime() == null) {
                t.setCrtTime(Calendar.getInstance().getTime());
            }
            if (t.getUpdTime() == null) {
                t.setUpdTime(Calendar.getInstance().getTime());
            }
            request.source(JSONArray.toJSONString(t), XContentType.JSON);
            indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            if (!esService.indexExist(indexName)) {
                Boolean isSuccess = esService.createIndex(indexName, getEntityClass());
                log.error("【save】error: 索引库{}不存在, 重新创建{}", indexName, isSuccess ? "成功！" : "失败！");
            }
        }
        DocWriteResponse.Result result = indexResponse.getResult();
        if (!"CREATED".equals(result.toString())) {
            log.error("【ES saveByDate】数据新增失败！ id: {}", t.getId());
            return false;
        } else {
            return true;
        }
    }

    /**
     * 批量插入数据
     *
     * @param tList
     */
    @Override
    @SneakyThrows
    public Boolean saveBatchByDate(List<T> tList) {
        if (CollectionUtils.isEmpty(tList)) {
            return false;
        }
        BulkRequest bulkRequest = new BulkRequest();
        String indexName = getIndexName(tList.get(0).getCrtTime());
        tList.forEach(t -> {
            String uuid = RandomUtils.getUUID();
            t.setDocId(uuid);
            if (t.getCrtTime() == null) {
                t.setCrtTime(Calendar.getInstance().getTime());
            }
            if (t.getUpdTime() == null) {
                t.setUpdTime(Calendar.getInstance().getTime());
            }
            bulkRequest.add(new IndexRequest(indexName).id(uuid).source(JSON.toJSONString(t), XContentType.JSON));
        });
        BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (!bulkResponse.hasFailures()) {
            log.debug("【ES saveBatch】数据批量插入成功！size: {}", tList.size());
            return true;
        } else {
            log.error("【ES saveBatch】数据批量插入失败！size: {}", tList.size());
            return false;
        }
    }


    /**
     * 指定索引库更新数据
     */
    @SneakyThrows
    @Override
    public Boolean updateByDate(T t) {
        // 拼接索引库名称
        String indexName = getIndexName(t.getCrtTime());
        RestStatus status = null;
        // 开始更新指定索引库下面的指定数据
        UpdateRequest updateRequest = new UpdateRequest(indexName, t.getDocId());
        updateRequest.timeout("3s");
        if (t.getUpdTime() == null) {
            t.setUpdTime(Calendar.getInstance().getTime());
        }
        updateRequest.doc(JSON.toJSONString(t), XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        status = update.status();
        if ("OK".equals(status.toString())) {
            log.debug("【ES updateByDate】数据更新成功：{}", JSON.toJSONString(t));
            return true;
        } else {
            log.error("【ES updateByDate】数据更新失败！");
            return false;
        }
    }

    /**
     * 指定索引库查询 (建议使用docId 对数据进行操作)
     *
     * @param id   数据id
     * @param date 查询对应时间的索引库
     * @return
     */
    @Override
    @SneakyThrows
    public List<T> selectByIdAndDate(Object id, Date date) {
        String indexName = getIndexName(date);
        if (id == null) {
            return null;
        }
        SearchHit[] hits = null;
        // 创建 searchRequest
        try {
            SearchRequest searchRequest = new SearchRequest(indexName);
            // 指定查询条件
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("id", id));
            // 组装sql
            sourceBuilder.query(boolQueryBuilder);
            searchRequest.source(sourceBuilder);
            //log.debug("DSL: {}", sourceBuilder.toString());
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            hits = searchResponse.getHits().getHits();
        } catch (Exception e) {
            if (!esService.indexExist(indexName)) {
                Boolean isSuccess = esService.createIndex(indexName, getEntityClass());
                log.error("【selectByIdAndDate】error: 索引库{}不存在, 重新创建{}", indexName, isSuccess ? "成功！" : "失败！");
            }
        }
        List<T> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            list.add(JSON.parseObject(hit.getSourceAsString(), getEntityClass()));
        }
        return list;
    }

    /**
     * 删除数据
     * 默认删除当天索引库的数据
     *
     * @param id   业务id
     * @param date
     * @return
     */
    @SneakyThrows
    @Override
    public Boolean deleteByIdAndDate(String id, Date date) {
        T t = selectByIdAndDate(id, date).get(0);
        if (t != null) {
            DeleteRequest deleteRequest = new DeleteRequest(getIndexName(), t.getDocId());
            deleteRequest.timeout("3s");
            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            RestStatus status = deleteResponse.status();
            if ("OK".equals(status.toString())) {
                log.debug("【ES deleteById】数据删除成功！id: {}", t.getDocId());
                return true;
            } else if ("NOT_FOUND".equals(status.toString())) {
                log.warn("【ES deleteById】数据不存在！id: {}", t.getDocId());
                return false;
            } else {
                log.error("【ES deleteById】数据删除失败！id: {}", t.getDocId());
                return false;
            }
        }
        return false;
    }


    /**
     * 分页查询
     * 匹配全部
     *
     * @param current
     * @param size
     * @return
     */
    @Override
    @SneakyThrows
    public Page<T> page(Integer current, Integer size) {
        // 创建搜索请求 指定索引库
        SearchRequest searchRequest = new SearchRequest(getIndexName());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder = initSearchSourceBuilder(searchSourceBuilder, current, size);
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        // 匹配全部
        boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        // 按照某个字段排序
        searchSourceBuilder.sort("crtTime", SortOrder.DESC);
        return pageBuilder(searchRequest, searchSourceBuilder, boolQueryBuilder, current, size);
    }

    /**
     * 判断doc是否存在
     */
    @Override
    @SneakyThrows
    public boolean dataIsExist(String docId) {
        GetRequest request = new GetRequest(getIndexName(), docId);
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
    }

    /**
     * 指定索引库判断doc是否存在
     */
    @SneakyThrows
    public boolean dataIsExist(String indexName, String docId) {
        GetRequest request = new GetRequest(indexName, docId);
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
    }


}
